/*
 * Copyright (c) 2019-2020, https://api.iot.10086.cn/(https://gitee.com/cmcc-iot-api/iot-card-open-application/).
 */
package cn.iot.card.open.sim.service;

import cn.iot.card.open.constants.Constants;
import cn.iot.card.open.constants.ErrorCode;
import cn.iot.card.open.constants.UrlConstants;
import cn.iot.card.open.ec.dto.ResponseDto;
import cn.iot.card.open.ec.dto.groupinfo.EcGroupOrderChangeableDTO;
import cn.iot.card.open.ec.dto.groupinfo.EcGroupOrderChangeableInfo;
import cn.iot.card.open.ec.warpper.EcGroupOfferingsWrapper;
import cn.iot.card.open.modular.model.ResultDTO;
import cn.iot.card.open.modular.token.TokenService;
import cn.iot.card.open.pojo.page.LayuiPageFactory;
import cn.iot.card.open.pojo.page.LayuiPageInfo;
import cn.iot.card.open.sim.dto.general.*;
import cn.iot.card.open.sim.warpper.GeneralBasicInfoWrapper;
import cn.iot.card.open.sim.warpper.GeneralHistoryStatusWrapper;
import cn.iot.card.open.util.ApiRequestUtil;
import cn.iot.card.open.util.CommonUtil;
import cn.iot.card.open.util.JsonUtil;
import cn.stylefeng.roses.core.reqres.response.ResponseData;
import cn.stylefeng.roses.core.util.ToolUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 物联卡综合信息-基本信息服务实现类
 *
 * @author 何光鑫
 * @date 20200313 14:52:26
 * @modify 20200313 何光鑫 v1.1.2 创建
 * @since v1.1.2
 */
@Service
@Slf4j
public class GeneralService {

    /**
     * 是否是最后一页
     */
    private static final String LASTPAGEFLAG = "N";

    /**
     * 上一次的页码
     */
    private long prePage = 1;

    /**
     * 上一次的总数
     */
    private long preTotal = 0;

    /**
     * 上一次的页条数
     */
    private long preSize = 0;

    @Autowired
    private ApiRequestUtil apiRequestUtil;

    @Autowired
    private TokenService tokenService;

    /**
     * 调用api接口查询物联卡综合信息-基本信息
     *
     * @param transId
     * @param accountId 集团id
     * @param cardType 卡号类型（msisdn、iccid、imsi一种）
     * @param cardTypes 批量卡号类型（msisdns、iccids、imsis一种）
     * @param cardNum 卡号（与类型对应）
     * @return 返回 layui page info
     * @throws IOException
     * @author 何光鑫
     * @date 20200313 14:52:26
     * @modify 20200313 何光鑫 v1.1.2 创建
     * @since v1.1.2
     */
    public LayuiPageInfo selectAllBasicInfo(String transId, String accountId, String cardType, String cardTypes, String cardNum) throws IOException {
        Map<String,Object> resultMap = new HashMap<>();
        // 调用api接口查询单卡基本信息
        Map<String, Object> basicInfoMap = queryBasicInfo(transId, accountId, cardType, cardNum);
        if(ToolUtil.isEmpty(basicInfoMap)){
            return LayuiPageFactory.createEmptyPageInfo();
        }
        if(ToolUtil.isNotEmpty(basicInfoMap.get(Constants.RESPONSE_ERROR))){
            ErrorCode errorCode = (ErrorCode)basicInfoMap.get(Constants.RESPONSE_ERROR);
            basicInfoMap.put(Constants.REQUEST_PARAM_MSISDN,errorCode.getMsg());
            basicInfoMap.put(Constants.REQUEST_PARAM_ICCID,errorCode.getMsg());
            basicInfoMap.put(Constants.REQUEST_PARAM_IMSI,errorCode.getMsg());
            basicInfoMap.put(Constants.RESPONSE_ACTIVE_DATE,errorCode.getMsg());
            basicInfoMap.put(Constants.RESPONSE_OPEN_DATE,errorCode.getMsg());
        }
        resultMap.putAll(basicInfoMap);

        // 调用api接口查询物联卡单卡状态
        Map<String, Object> simStatusMap = querySimStatus(transId, accountId, cardType, cardNum);
        if(ToolUtil.isEmpty(simStatusMap)){
            simStatusMap.put(Constants.RESPONSE_CARD_STATUS, Constants.BACK_REQUEST_NULL);
        } else if(ToolUtil.isNotEmpty(simStatusMap.get(Constants.RESPONSE_ERROR))){
            ErrorCode errorCode = (ErrorCode)simStatusMap.get(Constants.RESPONSE_ERROR);
            simStatusMap.put(Constants.RESPONSE_CARD_STATUS,errorCode.getMsg());
        }
        resultMap.putAll(simStatusMap);

        // 调用api接口查询物联卡开关状态
        Map<String, Object> onOffStatusMap = queryOnOffStatus(transId, accountId, cardType, cardNum);
        if(ToolUtil.isEmpty(onOffStatusMap)){
            onOffStatusMap.put(Constants.RESPONSE_ON_OFF_STATUS, Constants.BACK_REQUEST_NULL);
        } else if(ToolUtil.isNotEmpty(onOffStatusMap.get(Constants.RESPONSE_ERROR))){
            ErrorCode errorCode = (ErrorCode)onOffStatusMap.get(Constants.RESPONSE_ERROR);
            onOffStatusMap.put(Constants.RESPONSE_ON_OFF_STATUS,errorCode.getMsg());
        }
        resultMap.putAll(onOffStatusMap);

        // 调用api接口查询物联卡绑定的imei
        Map<String, Object> simImeiMap = querySimImei(transId, accountId, cardType, cardNum);
        if(ToolUtil.isEmpty(simImeiMap)){
            simImeiMap.put(Constants.RESPONSE_IMEI,Constants.BACK_REQUEST_NULL);
        } else if(ToolUtil.isNotEmpty(simImeiMap.get(Constants.RESPONSE_ERROR))){
            ErrorCode errorCode = (ErrorCode)simImeiMap.get(Constants.RESPONSE_ERROR);
            simImeiMap.put(Constants.RESPONSE_IMEI,errorCode.getMsg());
        }
        resultMap.putAll(simImeiMap);

        // 调用api接口查询物联卡归属平台
        Map<String, Object> platformMap = querySimPlatformBatch(transId, accountId, cardTypes, cardNum);
        if(ToolUtil.isEmpty(platformMap)){
            resultMap.put(Constants.RESPONSE_PLATFORM_TYPE,Constants.BACK_REQUEST_NULL);
        } else if (ToolUtil.isNotEmpty(platformMap.get(Constants.RESPONSE_ERROR))){
            ErrorCode errorCode = (ErrorCode)platformMap.get(Constants.RESPONSE_ERROR);
            resultMap.put(Constants.RESPONSE_PLATFORM_TYPE,errorCode.getMsg());
        } else {
            resultMap.put(Constants.RESPONSE_PLATFORM_TYPE,platformMap.get(Constants.RESPONSE_PLATFORM_TYPE));
        }

        // 调用api接口查询本月流量累计用量
        Map<String, Object> simDataUsageMap = querySimDataUsage(transId, accountId, cardType, cardNum);
        if(ToolUtil.isEmpty(simDataUsageMap)){
            simDataUsageMap.put(Constants.RESPONSE_DATA_AMOUNT,Constants.BACK_REQUEST_NULL);
        } else if(ToolUtil.isNotEmpty(simDataUsageMap.get(Constants.RESPONSE_ERROR))){
            ErrorCode errorCode = (ErrorCode)simDataUsageMap.get(Constants.RESPONSE_ERROR);
            simDataUsageMap.put(Constants.RESPONSE_DATA_AMOUNT,errorCode.getMsg());
        }
        resultMap.putAll(simDataUsageMap);

        // 调用api接口查询本月短信累计用量
        Map<String, Object> simSmsUsageMap = querySimSmsUsage(transId, accountId, cardType, cardNum);
        if(ToolUtil.isEmpty(simSmsUsageMap)){
            simSmsUsageMap.put(Constants.RESPONSE_SMS_AMOUNT,Constants.BACK_REQUEST_NULL);
        } else if(ToolUtil.isNotEmpty(simSmsUsageMap.get(Constants.RESPONSE_ERROR))){
            ErrorCode errorCode = (ErrorCode)simSmsUsageMap.get(Constants.RESPONSE_ERROR);
            simSmsUsageMap.put(Constants.RESPONSE_SMS_AMOUNT,errorCode.getMsg());
        }
        resultMap.putAll(simSmsUsageMap);

        // 调用api接口查询本月语音累计用量
        Map<String, Object> simVoiceUsageMap = querySimVoiceUsage(transId, accountId, cardType, cardNum);
        if(ToolUtil.isEmpty(simVoiceUsageMap)){
            simVoiceUsageMap.put(Constants.RESPONSE_VOICE_AMOUNT,Constants.BACK_REQUEST_NULL);
        } else if(ToolUtil.isNotEmpty(simVoiceUsageMap.get(Constants.RESPONSE_ERROR))){
            ErrorCode errorCode = (ErrorCode)simVoiceUsageMap.get(Constants.RESPONSE_ERROR);
            simVoiceUsageMap.put(Constants.RESPONSE_VOICE_AMOUNT,errorCode.getMsg());
        }
        resultMap.putAll(simVoiceUsageMap);

        // 调用api接口查询物联卡余额
        Map<String, Object> balanceInfoMap = queryBalanceInfo(transId, accountId, cardType, cardNum);
        if(ToolUtil.isEmpty(balanceInfoMap)){
            balanceInfoMap.put(Constants.RESPONSE_AMOUNT,Constants.BACK_REQUEST_NULL);
            //返回前端错误标识，为1时有错误
            balanceInfoMap.put(Constants.RESPONSE_ERROR_CODE,Constants.RESPONSE_ECHARTS_ERROR);
        } else if(ToolUtil.isNotEmpty(balanceInfoMap.get(Constants.RESPONSE_ERROR))){
            ErrorCode errorCode = (ErrorCode)balanceInfoMap.get(Constants.RESPONSE_ERROR);
            balanceInfoMap.put(Constants.RESPONSE_AMOUNT,errorCode.getMsg());
            //返回前端错误标识，为1时有错误
            balanceInfoMap.put(Constants.RESPONSE_ERROR_CODE,Constants.RESPONSE_ECHARTS_ERROR);
        } else {
            balanceInfoMap.put(Constants.RESPONSE_ERROR_CODE,Constants.RESPONSE_ECHARTS_RIGHT);
        }
        resultMap.putAll(balanceInfoMap);
        resultMap.put(Constants.RESPONSE_ACCOUNT_ID,accountId);

        //封装参数
        List<Map<String,Object>> resultListMaps = new ArrayList<>();
        resultListMaps.add(resultMap);
        Page page = LayuiPageFactory.defaultPage();
        page.setRecords(resultListMaps);
        Page wrapped = new GeneralBasicInfoWrapper(page).wrap();
        return LayuiPageFactory.createPageInfo(wrapped);
    }

    /**
     * 调用api接口按查询条件查询物联卡基本信息.
     *
     * @param transId
     * @param accountId 集团id
     * @param cardType 卡号类型（msisdn、iccid、imsi一种）
     * @param cardNum 卡号（与类型对应）
     * @return 返回 map
     * @throws IOException
     * @author 何光鑫
     * @date 20200313 14:52:26
     * @modify 20200313 何光鑫 v1.1.2 创建
     * @since v1.1.2
     */
    public Map<String,Object> queryBasicInfo(String transId, String accountId, String cardType,String cardNum) throws IOException {
        Map<String, Object> resultMap = new HashMap<>();
        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put(cardType,cardNum);
        String url = UrlConstants.SIM_BASIC_INFO;
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO tokenResultDTO = doRequest(true, accountId, transId, parameterMap,url);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
            log.warn("[{}] query basicInfo token error first,error message is {}.",transId, errorCode.getMsg());
            resultMap.put(Constants.RESPONSE_ERROR,errorCode);
            return resultMap;
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = tokenResultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token[accountId:{}] of query basicInfo is invalid and start to get a new token.", transId, accountId);
            tokenResultDTO = doRequest(false, accountId, transId,  parameterMap,url);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
                log.warn("[{}] query basicInfo token error second,error message is {}.",transId, errorCode.getMsg());
                resultMap.put(Constants.RESPONSE_ERROR,errorCode);
                return resultMap;
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = tokenResultDTO.getMsg();
        }
        log.info("[{}] query basicInfo result string is {}.", transId, responseStr);
        // 解析api响应结果
        ResponseDto<BasicInfoDTO> result = JsonUtil.parseJson(responseStr, new TypeReference<ResponseDto<BasicInfoDTO>>() {});
        code = result.getStatus();
        if (!ErrorCode.SUCCESS.getCode().equals(code)) {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] query basicInfo error,error message is {}.", transId, result.getMessage());
            ErrorCode errorCode = ErrorCode.getByCode(code);
            resultMap.put(Constants.RESPONSE_ERROR,errorCode);
            return resultMap;
        }
        List<BasicInfoDTO> basicInfoDTOS = result.getResult();
        if (ToolUtil.isEmpty(basicInfoDTOS)) {
            log.warn("[{}] query basicInfo end,result is null.", transId);
            return resultMap;
        }
        BasicInfoDTO basicInfoDTO = basicInfoDTOS.get(0);
        if (ToolUtil.isEmpty(basicInfoDTO)) {
            log.warn("[{}] query basicInfo end,result is null.", transId);
            return resultMap;
        }
        resultMap.put(Constants.REQUEST_PARAM_MSISDN,basicInfoDTO.getMsisdn());
        resultMap.put(Constants.REQUEST_PARAM_ICCID,basicInfoDTO.getIccid());
        resultMap.put(Constants.REQUEST_PARAM_IMSI,basicInfoDTO.getImsi());
        resultMap.put(Constants.RESPONSE_ACTIVE_DATE,basicInfoDTO.getActiveDate());
        resultMap.put(Constants.RESPONSE_OPEN_DATE,basicInfoDTO.getOpenDate());
        return resultMap;
    }

    /**
     * 调用api接口查询物联卡单卡状态.
     *
     * @param transId
     * @param accountId 集团id
     * @param cardType 卡号类型（msisdn、iccid、imsi一种）
     * @param cardNum 卡号（与类型对应）
     * @return 返回 map
     * @throws IOException
     * @author 何光鑫
     * @date 20200313 14:52:26
     * @modify 20200313 何光鑫 v1.1.2 创建
     * @since v1.1.2
     */
    private Map<String,Object> querySimStatus(String transId, String accountId, String cardType,String cardNum) throws IOException {
        Map<String, Object> resultMap = new HashMap<>();
        // 封装调用api接口的参数
        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put(cardType,cardNum);
        String url = UrlConstants.SIM_STATUS;
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO tokenResultDTO = doRequest(true, accountId, transId, parameterMap,url);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
            log.warn("[{}] query simStatus token error first,error message is {}.",transId, errorCode.getMsg());
            resultMap.put(Constants.RESPONSE_ERROR,errorCode);
            return resultMap;
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = tokenResultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token[accountId:{}] of query simStatus is invalid and start to get a new token.", transId, accountId);
            tokenResultDTO = doRequest(false, accountId, transId,  parameterMap,url);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
                log.warn("[{}] query simStatus token error second,error message is {}.",transId, errorCode.getMsg());
                resultMap.put(Constants.RESPONSE_ERROR,errorCode);
                return resultMap;
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = tokenResultDTO.getMsg();
        }
        log.info("[{}] query simStatus result string is {}.", transId, responseStr);
        // 解析api响应结果
        ResponseDto<SimStatusDTO> result = JsonUtil.parseJson(responseStr, new TypeReference<ResponseDto<SimStatusDTO>>() {});
        code = result.getStatus();
        if (!ErrorCode.SUCCESS.getCode().equals(code)) {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] query simStatus error,error message is {}.", transId, result.getMessage());
            ErrorCode errorCode = ErrorCode.getByCode(code);
            resultMap.put(Constants.RESPONSE_ERROR,errorCode);
            return resultMap;
        }
        List<SimStatusDTO> simStatusDTOS = result.getResult();
        if (ToolUtil.isEmpty(simStatusDTOS)) {
            log.warn("[{}] query simStatus end,result is null.", transId);
            return resultMap;
        }
        SimStatusDTO simStatusDTO = simStatusDTOS.get(0);
        if (ToolUtil.isEmpty(simStatusDTO)) {
            log.warn("[{}] query simStatus end,result is null.", transId);
            return resultMap;
        }
        resultMap.put(Constants.RESPONSE_CARD_STATUS,simStatusDTO.getCardStatus());
        resultMap.put(Constants.RESPONSE_LAST_CHANGE_DATE,simStatusDTO.getLastChangeDate());
        return resultMap;
    }

    /**
     * 调用api接口查询物联卡单卡卡开关状态.
     *
     * @param transId
     * @param accountId 集团id
     * @param cardType 卡号类型（msisdn、iccid、imsi一种）
     * @param cardNum 卡号（与类型对应）
     * @return 返回 map
     * @throws IOException
     * @author 何光鑫
     * @date 20200313 14:52:26
     * @modify 20200313 何光鑫 v1.1.2 创建
     * @since v1.1.2
     */
    private Map<String,Object> queryOnOffStatus(String transId, String accountId, String cardType,String cardNum) throws IOException {
        Map<String, Object> resultMap = new HashMap<>();
        // 封装调用api接口的参数
        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put(cardType,cardNum);
        String url = UrlConstants.ON_OFF_STATUS;
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO tokenResultDTO = doRequest(true, accountId, transId, parameterMap,url);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
            log.warn("[{}] query onOffStatus token error first,error message is {}.",transId, errorCode.getMsg());
            resultMap.put(Constants.RESPONSE_ERROR,errorCode);
            return resultMap;
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = tokenResultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token[accountId:{}] of query onOffStatus is invalid and start to get a new token.", transId, accountId);
            tokenResultDTO = doRequest(false, accountId, transId,  parameterMap,url);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
                log.warn("[{}] query onOffStatus token error second,error message is {}.",transId, errorCode.getMsg());
                resultMap.put(Constants.RESPONSE_ERROR,errorCode);
                return resultMap;
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = tokenResultDTO.getMsg();
        }
        log.info("[{}] query onOffStatus result string is {}.", transId, responseStr);
        // 解析api响应结果
        ResponseDto<OnOffStatusDTO> result = JsonUtil.parseJson(responseStr, new TypeReference<ResponseDto<OnOffStatusDTO>>() {});
        code = result.getStatus();
        if (!ErrorCode.SUCCESS.getCode().equals(code)) {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] query onOffStatus error,error message is {}.", transId, result.getMessage());
            ErrorCode errorCode = ErrorCode.getByCode(code);
            resultMap.put(Constants.RESPONSE_ERROR,errorCode);
            return resultMap;
        }
        List<OnOffStatusDTO> onOffStatusDTOS = result.getResult();
        if (ToolUtil.isEmpty(onOffStatusDTOS)) {
            log.warn("[{}] query onOffStatus end,result is null.", transId);
            return resultMap;
        }
        OnOffStatusDTO onOffStatusDTO = onOffStatusDTOS.get(0);
        if (ToolUtil.isEmpty(onOffStatusDTO)) {
            log.warn("[{}] query onOffStatus end,result is null.", transId);
            return resultMap;
        }
        resultMap.put(Constants.RESPONSE_ON_OFF_STATUS,onOffStatusDTO.getStatus());
        return resultMap;
    }

    /**
     * 调用api接口查询物联卡绑定IMEI.
     *
     * @param transId
     * @param accountId 集团id
     * @param cardType 卡号类型（msisdn、iccid、imsi一种）
     * @param cardNum 卡号（与类型对应）
     * @return 返回 map
     * @throws IOException
     * @author 何光鑫
     * @date 20200313 14:52:27
     * @modify 20200313 何光鑫 v1.1.2 创建
     * @since v1.1.2
     */
    private Map<String,Object> querySimImei(String transId, String accountId, String cardType,String cardNum) throws IOException {
        Map<String, Object> resultMap = new HashMap<>();
        // 封装调用api接口的参数
        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put(cardType,cardNum);
        String url = UrlConstants.SIM_IMEI;
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO tokenResultDTO = doRequest(true, accountId, transId, parameterMap,url);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
            log.warn("[{}] query simImei token error first,error message is {}.",transId, errorCode.getMsg());
            resultMap.put(Constants.RESPONSE_ERROR,errorCode);
            return resultMap;
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = tokenResultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token[accountId:{}] of query simImei is invalid and start to get a new token.", transId, accountId);
            tokenResultDTO = doRequest(false, accountId, transId,  parameterMap,url);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
                log.warn("[{}] query simImei token error second,error message is {}.",transId, errorCode.getMsg());
                resultMap.put(Constants.RESPONSE_ERROR,errorCode);
                return resultMap;
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = tokenResultDTO.getMsg();
        }
        log.info("[{}] query simImei result string is {}.", transId, responseStr);
        // 解析api响应结果
        ResponseDto<SimImeiDTO> result = JsonUtil.parseJson(responseStr, new TypeReference<ResponseDto<SimImeiDTO>>() {});
        code = result.getStatus();
        if (!ErrorCode.SUCCESS.getCode().equals(code)) {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] query simImei error,error message is {}.", transId, result.getMessage());
            ErrorCode errorCode = ErrorCode.getByCode(code);
            resultMap.put(Constants.RESPONSE_ERROR,errorCode);
            return resultMap;
        }
        List<SimImeiDTO> simImeiDTOS = result.getResult();
        if (ToolUtil.isEmpty(simImeiDTOS)) {
            log.warn("[{}] query simImei end,result is null.", transId);
            return resultMap;
        }
        SimImeiDTO simImeiDTO = simImeiDTOS.get(0);
        if (ToolUtil.isEmpty(simImeiDTO)) {
            log.warn("[{}] query simImei end,result is null.", transId);
            return resultMap;
        }
        resultMap.put(Constants.RESPONSE_IMEI,simImeiDTO.getImei());
        return resultMap;
    }

    /**
     * 调用api接口查询物联卡归属的平台
     *
     * @param transId
     * @param accountId 集团id
     * @param cardTypes 批量卡号类型（msisdns、iccids、imsis一种）
     * @param cardNum 卡号（与类型对应）
     * @return 返回 map
     * @throws IOException
     * @author 何光鑫
     * @date 20200313 14:52:27
     * @modify 20200313 何光鑫 v1.1.2 创建
     * @since v1.1.2
     */
    private Map<String,Object> querySimPlatformBatch(String transId, String accountId, String cardTypes,String cardNum) throws IOException {
        Map<String, Object> resultMap = new HashMap<>();
        // 封装调用api接口的参数
        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put(cardTypes,cardNum);
        String url = UrlConstants.SIM_PLATFORM_BATCH;
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO tokenResultDTO = doRequest(true, accountId, transId, parameterMap,url);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
            log.warn("[{}] query simPlatformBatch token error first,error message is {}.",transId, errorCode.getMsg());
            resultMap.put(Constants.RESPONSE_ERROR,errorCode);
            return resultMap;
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = tokenResultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token[accountId:{}] of query simPlatformBatch is invalid and start to get a new token.", transId, accountId);
            tokenResultDTO = doRequest(false, accountId, transId,  parameterMap,url);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
                log.warn("[{}] query simPlatformBatch token error second,error message is {}.",transId, errorCode.getMsg());
                resultMap.put(Constants.RESPONSE_ERROR,errorCode);
                return resultMap;
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = tokenResultDTO.getMsg();
        }
        log.info("[{}] query simPlatformBatch result string is {}.", transId, responseStr);
        // 解析api响应结果
        ResponseDto<SimPlatformDTO> result = JsonUtil.parseJson(responseStr, new TypeReference<ResponseDto<SimPlatformDTO>>() {});
        code = result.getStatus();
        if (!ErrorCode.SUCCESS.getCode().equals(code)) {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] query simPlatformBatch error,error message is {}.", transId, result.getMessage());
            ErrorCode errorCode = ErrorCode.getByCode(code);
            resultMap.put(Constants.RESPONSE_ERROR,errorCode);
            return resultMap;
        }
        List<SimPlatformDTO> simPlatformDTOS = result.getResult();
        if (ToolUtil.isEmpty(simPlatformDTOS)) {
            log.warn("[{}] query simPlatformBatch end,result is null.", transId);
            return resultMap;
        }
        //封装参数
        SimPlatformDTO simPlatformDTO = simPlatformDTOS.get(0);
        resultMap.put(Constants.RESPONSE_STATUS,simPlatformDTO.getStatus());
        resultMap.put(Constants.RESPONSE_MESSAGE,simPlatformDTO.getMessage());
        resultMap.put(Constants.REQUEST_PARAM_MSISDN,simPlatformDTO.getMsisdn());
        resultMap.put(Constants.REQUEST_PARAM_ICCID,simPlatformDTO.getIccid());
        resultMap.put(Constants.REQUEST_PARAM_IMSI,simPlatformDTO.getImsi());
        resultMap.put(Constants.RESPONSE_PLATFORM_TYPE,simPlatformDTO.getPlatformType());
        return resultMap;
    }

    /**
     * 调用api接口查询物联卡本月流量累计用量（KB）.
     *
     * @param transId
     * @param accountId 集团id
     * @param cardType 卡号类型（msisdn、iccid、imsi一种）
     * @param cardNum 卡号（与类型对应）
     * @return 返回 map
     * @throws IOException
     * @author 何光鑫
     * @date 20200313 14:52:27
     * @modify 20200313 何光鑫 v1.1.2 创建
     * @since v1.1.2
     */
    private Map<String,Object> querySimDataUsage(String transId, String accountId, String cardType,String cardNum) throws IOException {
        Map<String, Object> resultMap = new HashMap<>();
        // 封装调用api接口的参数
        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put(cardType,cardNum);
        String url = UrlConstants.SIM_DATA_USAGE;
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO tokenResultDTO = doRequest(true, accountId, transId, parameterMap,url);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
            log.warn("[{}] query simDataUsage token error first,error message is {}.",transId, errorCode.getMsg());
            resultMap.put(Constants.RESPONSE_ERROR,errorCode);
            return resultMap;
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = tokenResultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token[accountId:{}] of query simDataUsage  is invalid and start to get a new token.", transId, accountId);
            tokenResultDTO = doRequest(false, accountId, transId,  parameterMap,url);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
                log.warn("[{}] query simDataUsage token error second,error message is {}.",transId, errorCode.getMsg());
                resultMap.put(Constants.RESPONSE_ERROR,errorCode);
                return resultMap;
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = tokenResultDTO.getMsg();
        }
        log.info("[{}] query simDataUsage result string is {}.", transId, responseStr);
        // 解析api响应结果
        ResponseDto<SimDataUsageDTO> result = JsonUtil.parseJson(responseStr, new TypeReference<ResponseDto<SimDataUsageDTO>>() {});
        code = result.getStatus();
        if (!ErrorCode.SUCCESS.getCode().equals(code)) {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] query simDataUsage error,error message is {}.", transId, result.getMessage());
            ErrorCode errorCode = ErrorCode.getByCode(code);
            resultMap.put(Constants.RESPONSE_ERROR,errorCode);
            return resultMap;
        }
        List<SimDataUsageDTO> simDataUsageDTOS = result.getResult();
        if (ToolUtil.isEmpty(simDataUsageDTOS)) {
            log.warn("[{}] query simDataUsage end,result is null.", transId);
            return resultMap;
        }
        SimDataUsageDTO simDataUsageDTO = simDataUsageDTOS.get(0);
        if (ToolUtil.isEmpty(simDataUsageDTO)) {
            log.warn("[{}] query simDataUsage end,result is null.", transId);
            return resultMap;
        }
        resultMap.put(Constants.RESPONSE_DATA_AMOUNT,simDataUsageDTO.getDataAmount());
        return resultMap;
    }

    /**
     * 调用api接口查询物联卡本月短信累计用量（条).
     *
     * @param transId
     * @param accountId 集团id
     * @param cardType 卡号类型（msisdn、iccid、imsi一种）
     * @param cardNum 卡号（与类型对应）
     * @return 返回 map
     * @throws IOException
     * @author 何光鑫
     * @date 20200313 14:52:27
     * @modify 20200313 何光鑫 v1.1.2 创建
     * @since v1.1.2
     */
    private Map<String,Object> querySimSmsUsage(String transId, String accountId, String cardType,String cardNum) throws IOException {
        Map<String, Object> resultMap = new HashMap<>();
        // 封装调用api接口的参数
        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put(cardType,cardNum);
        String url = UrlConstants.SIM_SMS_USAGE;
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO tokenResultDTO = doRequest(true, accountId, transId, parameterMap,url);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
            log.warn("[{}] query simSmsUsage token error first,error message is {}.",transId, errorCode.getMsg());
            resultMap.put(Constants.RESPONSE_ERROR,errorCode);
            return resultMap;
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = tokenResultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token[accountId:{}] of query simSmsUsage is invalid and start to get a new token.", transId, accountId);
            tokenResultDTO = doRequest(false, accountId, transId,  parameterMap,url);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
                log.warn("{} query simSmsUsage token error second,error message is {}.",transId, errorCode.getMsg());
                resultMap.put(Constants.RESPONSE_ERROR,errorCode);
                return resultMap;
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = tokenResultDTO.getMsg();
        }
        log.info("[{}] query simSmsUsage result string is {}.", transId, responseStr);
        // 解析api响应结果
        ResponseDto<SimSmsUsageDTO> result = JsonUtil.parseJson(responseStr, new TypeReference<ResponseDto<SimSmsUsageDTO>>() {});
        code = result.getStatus();
        if (!ErrorCode.SUCCESS.getCode().equals(code)) {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] query simSmsUsage error,error message is {}.", transId, result.getMessage());
            ErrorCode errorCode = ErrorCode.getByCode(code);
            resultMap.put(Constants.RESPONSE_ERROR,errorCode);
            return resultMap;
        }
        List<SimSmsUsageDTO> simSmsUsageDTOS = result.getResult();
        if (ToolUtil.isEmpty(simSmsUsageDTOS)) {
            log.warn("[{}] query simSmsUsage end,result is null.", transId);
            return resultMap;
        }
        SimSmsUsageDTO simSmsUsageDTO = simSmsUsageDTOS.get(0);
        if (ToolUtil.isEmpty(simSmsUsageDTO)) {
            log.warn("[{}] query simSmsUsage end,result is null.", transId);
            return resultMap;
        }
        resultMap.put(Constants.RESPONSE_SMS_AMOUNT,simSmsUsageDTO.getSmsAmount());
        return resultMap;
    }

    /**
     * 调用api接口查询物联卡本月语音累计用量（分钟).
     *
     * @param transId
     * @param accountId 集团id
     * @param cardType 卡号类型（msisdn、iccid、imsi一种）
     * @param cardNum 卡号（与类型对应）
     * @return 返回 map
     * @throws IOException
     * @author 何光鑫
     * @date 20200313 14:52:27
     * @modify 20200313 何光鑫 v1.1.2 创建
     * @since v1.1.2
     */
    private Map<String,Object> querySimVoiceUsage(String transId, String accountId, String cardType,String cardNum) throws IOException {
        Map<String, Object> resultMap = new HashMap<>();
        // 封装调用api接口的参数
        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put(cardType,cardNum);
        String url = UrlConstants.SIM_VOICE_USAGE;
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO tokenResultDTO = doRequest(true, accountId, transId, parameterMap,url);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
            log.warn("[{}] query simVoiceUsage token error first,error message is {}.",transId, errorCode.getMsg());
            resultMap.put(Constants.RESPONSE_ERROR,errorCode);
            return resultMap;
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = tokenResultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token[accountId:{}] of query simVoiceUsage is invalid and start to get a new token.", transId, accountId);
            tokenResultDTO = doRequest(false, accountId, transId,  parameterMap,url);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
                log.warn("{} query simVoiceUsage token error second,error message is {}.",transId, errorCode.getMsg());
                resultMap.put(Constants.RESPONSE_ERROR,errorCode);
                return resultMap;
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = tokenResultDTO.getMsg();
        }
        log.info("[{}] query simVoiceUsage result string is {}.", transId, responseStr);
        // 解析api响应结果
        ResponseDto<SimVoiceUsageDTO> result = JsonUtil.parseJson(responseStr, new TypeReference<ResponseDto<SimVoiceUsageDTO>>() {});
        code = result.getStatus();
        if (!ErrorCode.SUCCESS.getCode().equals(code)) {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] query simVoiceUsage error,error message is {}.", transId, result.getMessage());
            ErrorCode errorCode = ErrorCode.getByCode(code);
            resultMap.put(Constants.RESPONSE_ERROR,errorCode);
            return resultMap;
        }
        List<SimVoiceUsageDTO> simVoiceUsageDTOS = result.getResult();
        if (ToolUtil.isEmpty(simVoiceUsageDTOS)) {
            log.warn("[{}] query simVoiceUsage end,result is null.", transId);
            return resultMap;
        }
        SimVoiceUsageDTO simVoiceUsageDTO = simVoiceUsageDTOS.get(0);
        if (ToolUtil.isEmpty(simVoiceUsageDTO)) {
            log.warn("[{}] query simVoiceUsage end,result is null.", transId);
            return resultMap;
        }
        resultMap.put(Constants.RESPONSE_VOICE_AMOUNT,simVoiceUsageDTO.getVoiceAmount());
        return resultMap;
    }

    /**
     * 调用api接口查询物联卡余额信息.
     *
     * @param transId
     * @param accountId 集团id
     * @param cardType 卡号类型（msisdn、iccid、imsi一种）
     * @param cardNum 卡号（与类型对应）
     * @return 返回 map
     * @throws IOException
     * @author 何光鑫
     * @date 20200313 14:52:27
     * @modify 20200313 何光鑫 v1.1.2 创建
     * @since v1.1.2
     */
    public Map<String,Object> queryBalanceInfo(String transId, String accountId, String cardType,String cardNum) throws IOException {
        Map<String, Object> resultMap = new HashMap<>();
        // 封装调用api接口的参数
        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put(cardType,cardNum);
        String url = UrlConstants.BAlANCE_INFO;
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO tokenResultDTO = doRequest(true, accountId, transId, parameterMap,url);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
            log.warn("[{}] query balanceInfo token error first,error message is {}.",transId, errorCode.getMsg());
            resultMap.put(Constants.RESPONSE_ERROR,errorCode);
            return resultMap;
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = tokenResultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token[accountId:{}] of query balanceInfo is invalid and start to get a new token.", transId, accountId);
            tokenResultDTO = doRequest(false, accountId, transId,  parameterMap,url);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
                log.warn("[{}] query balanceInfo token error second,error message is {}.",transId, errorCode.getMsg());
                resultMap.put(Constants.RESPONSE_ERROR,errorCode);
                return resultMap;
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = tokenResultDTO.getMsg();
        }
        log.info("[{}] query balanceInfo result string is {}.", transId, responseStr);
        // 解析api响应结果
        ResponseDto<BalanceInfoDTO> result = JsonUtil.parseJson(responseStr, new TypeReference<ResponseDto<BalanceInfoDTO>>() {});
        code = result.getStatus();
        if (!ErrorCode.SUCCESS.getCode().equals(code)) {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] query balanceInfo error,error message is {}.", transId, result.getMessage());
            ErrorCode errorCode = ErrorCode.getByCode(code);
            resultMap.put(Constants.RESPONSE_ERROR,errorCode);
            return resultMap;
        }
        List<BalanceInfoDTO> balanceInfoDTOS = result.getResult();
        if (ToolUtil.isEmpty(balanceInfoDTOS)) {
            log.warn("[{}] query balanceInfo end,result is null.", transId);
            return resultMap;
        }
        BalanceInfoDTO balanceInfoDTO = balanceInfoDTOS.get(0);
        if (ToolUtil.isEmpty(balanceInfoDTO)) {
            log.warn("[{}] query balanceInfo end,result is null.", transId);
            return resultMap;
        }
        resultMap.put(Constants.RESPONSE_ACCOUNT_ID,balanceInfoDTO.getAccountId());
        resultMap.put(Constants.RESPONSE_ACCOUNT_NAME,balanceInfoDTO.getAccountName());
        resultMap.put(Constants.RESPONSE_AMOUNT,balanceInfoDTO.getAmount());
        return resultMap;
    }

    /**
     * 调用api接口查询物联卡归属群组信息.
     *
     * @param transId
     * @param accountId 集团id
     * @param cardType 卡号类型（msisdn、iccid、imsi一种）
     * @param cardNum 卡号（与类型对应）
     * @return 返回 layui page info
     * @throws IOException
     * @author 何光鑫
     * @date 20200313 14:52:27
     * @modify 20200313 何光鑫 v1.1.2 创建
     * @since v1.1.2
     */
    public LayuiPageInfo queryGroupByMember(String transId, String accountId,String cardType,String cardNum) throws IOException {
        // 封装调用api接口的参数
        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put(cardType,cardNum);
        String url = UrlConstants.GROUP_BY_MEMBER;
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO tokenResultDTO = doRequest(true, accountId, transId, parameterMap,url);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
            log.warn("[{}] query groupByMember token error first,error message is {}.",transId, errorCode);
            return LayuiPageFactory.cteateErrorMsg(errorCode);
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = tokenResultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token[accountId:{}] of query groupByMember is invalid and start to get a new token.", transId, accountId);
            tokenResultDTO = doRequest(false, accountId, transId, parameterMap,url);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
                log.warn("[{}] query groupByMember token error second,error message is {}.",transId, errorCode);
                return LayuiPageFactory.cteateErrorMsg(errorCode);
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = tokenResultDTO.getMsg();
        }
        log.info("[{}] query groupByMember result string is {}.", transId, responseStr);
        // 组装页面信息
        ResponseDto<GeneralGroupDTO> result = JsonUtil.parseJson(responseStr, new TypeReference<ResponseDto<GeneralGroupDTO>>() {});
        code = result.getStatus();
        // 如果api接口返回失败，则返回失败原因
        if (!ErrorCode.SUCCESS.getCode().equals(code)) {
            log.warn("[{}] query groupByMember error,error message is {}.", transId, result.getMessage());
            return LayuiPageFactory.cteateErrorMsg(ErrorCode.getByCode(code));
        }
        List<GeneralGroupDTO> generalGroupDTOS = result.getResult();
        if (ToolUtil.isEmpty(generalGroupDTOS)) {
            log.warn("[{}] query groupByMember end,result is null.", transId);
        }
        List<GroupListDTO> groupListDTOList = generalGroupDTOS.get(0).getGroupList();
        Page page = LayuiPageFactory.defaultPage();
        page.setTotal(groupListDTOList.size());
        page.setRecords(groupListDTOList);
        return LayuiPageFactory.createPageInfo(page);
    }

    /**
     * 调用api接口查询物联卡可变更资费
     *
     * @param transId
     * @param accountId 集团id
     * @param parameterMap 查询物联卡可变更资费的参数
     * @return 返回 layui page info
     * @throws IOException
     * @author 何光鑫
     * @date 20200313 14:52:27
     * @modify 20200313 何光鑫 v1.1.2 创建
     * @since v1.1.2
     */
    public LayuiPageInfo queryChangeableOfferings(String transId, String accountId,Map<String, String> parameterMap) throws IOException {
        // 封装调用api接口的参数
        Page page = LayuiPageFactory.defaultPage();
        String startNum = String.valueOf(page.getCurrent());
        String pageSize = String.valueOf(page.getSize());
        parameterMap.put(Constants.REQUEST_PARAM_STARTNUM, startNum);
        parameterMap.put(Constants.REQUEST_PARAM_PAGESIZE, pageSize);
        String url = UrlConstants.QUERY_CHANGEABLE_OFFERINGS;
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO tokenResultDTO = doRequest(true, accountId, transId, parameterMap,url);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
            log.warn("[{}] query changeableOfferings token error first,error message is {}.",transId, errorCode);
            return LayuiPageFactory.cteateErrorMsg(errorCode);
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = tokenResultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token[accountId:{}] of query changeableOfferings is invalid and start to get a new token.", transId, accountId);
            tokenResultDTO = doRequest(false, accountId, transId, parameterMap,url);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
                log.warn("[{}] query changeableOfferings token error second,error message is {}.",transId, errorCode);
                return LayuiPageFactory.cteateErrorMsg(errorCode);
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = tokenResultDTO.getMsg();
        }
        log.info("[{}] query changeableOfferings result string is {}.", transId, responseStr);
        // 组装页面信息
        ResponseDto<EcGroupOrderChangeableDTO> result = JsonUtil.parseJson(responseStr, new TypeReference<ResponseDto<EcGroupOrderChangeableDTO>>() {});
        code = result.getStatus();
        if (!ErrorCode.SUCCESS.getCode().equals(code)) {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] query changeableOfferings error,error message is {}.", transId, result.getMessage());
            return LayuiPageFactory.cteateErrorMsg(ErrorCode.getByCode(code));
        }
        List<EcGroupOrderChangeableDTO> groupVoices = result.getResult();
        if (ToolUtil.isEmpty(groupVoices)) {
            log.warn("[{}] query changeableOfferings end,result is null.", transId);
            return LayuiPageFactory.createEmptyPageInfo();
        }
        EcGroupOrderChangeableDTO ecGroupOrderChangeableDTO = groupVoices.get(0);
        List<EcGroupOrderChangeableInfo> groupList = ecGroupOrderChangeableDTO.getOfferingInfoList();
        String groupListStr = JsonUtil.toJson(groupList);
        List<Map<String,Object>> groupListMaps = JsonUtil.parseJson(groupListStr, new TypeReference<List<Map<String,Object>>>(){});
        // 后一页
        if (page.getCurrent() > prePage) {
            if (LASTPAGEFLAG.equals(ecGroupOrderChangeableDTO.getFlag())) {
                // 如果不是最后一页，设置总数超过当前数，点亮下一页按钮
                preTotal = preSize * page.getCurrent();
                page.setTotal(preTotal + 1);
            } else {
                preTotal = groupListMaps.size() + preSize * prePage;
                page.setTotal(preTotal);
            }
        } else if (page.getCurrent() == 1){
            // 第一页
            preSize = groupListMaps.size();
            if (LASTPAGEFLAG.equals(ecGroupOrderChangeableDTO.getFlag())) {
                // 如果不是最后一页，设置总数超过当前数，点亮下一页按钮
                page.setTotal(preSize + 1);
            } else {
                page.setTotal(preSize);
            }
            preTotal = preSize;
        } else {
            // 前一页
            page.setTotal(preTotal);
        }
        prePage = page.getCurrent();
        preSize = groupListMaps.size();
        page.setRecords(groupListMaps);
        Page wrapped = new EcGroupOfferingsWrapper(page).wrap();
        return LayuiPageFactory.createPageInfo(wrapped);
    }

    /**
     * 调用api接口变更物联卡状态
     *
     * @param transId
     * @param accountId 集团id
     * @param parameterMap 查询物联卡可变更资费的参数
     * @return 返回 map
     * @throws IOException
     * @author 何光鑫
     * @date 20200315 13:09:11
     * @modify 20200315 何光鑫 v1.1.2 创建
     * @since v1.1.2
     */
    public ResponseData changeSimStatus(String transId, String accountId, Map<String, String> parameterMap) throws IOException {
        ResponseData responseData = new ResponseData();
        // 调用api接口：先获取token，然后带着token调用api接口
        String url = UrlConstants.CHANGE_SIM_STATUS;
        ResultDTO tokenResultDTO = doRequest(true, accountId, transId, parameterMap,url);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
            log.warn("[{}] query changeSimStatus token error first,error message is {}.",transId, errorCode.getMsg());
            responseData.setCode(Integer.valueOf(errorCode.getCode()));
            responseData.setMessage(errorCode.getMsg());
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = tokenResultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token[accountId:{}] of query changeSimStatus is invalid and start to get a new token.", transId, accountId);
            tokenResultDTO = doRequest(false, accountId, transId,  parameterMap,url);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
                log.warn("[{}] query changeSimStatus token error second,error message is {}.",transId, errorCode.getMsg());
                responseData.setCode(Integer.valueOf(errorCode.getCode()));
                responseData.setMessage(errorCode.getMsg());
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = tokenResultDTO.getMsg();
        }

        log.info("[{}] changeSimStatus result string is {}.", transId, responseStr);
        // 解析api响应结果
        ResponseDto<Map<String, String>> responseDto = JsonUtil.parseJson(responseStr,
                new TypeReference<ResponseDto<Map<String, String>>>(){});
        code = responseDto.getStatus();
        if (ErrorCode.SUCCESS.getCode().equals(code)) {
            return ResponseData.success(JsonUtil.toJson(responseDto.getResult()));
        } else {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] reset changeSimStatus error, error message is {}.", transId, responseDto.getMessage());
            responseData = new ResponseData();
            responseData.setCode(Integer.valueOf(code));
            responseData.setMessage(responseDto.getMessage());
            return responseData;
        }
    }

    /**
     * 调用api接口查询物联卡状态变更历史
     *
     * @param transId
     * @param accountId 集团id
     * @param parameterMap 查询物联卡状态变更历史的参数
     * @return 返回 layui page info
     * @throws IOException
     * @author 何光鑫
     * @date 20200316 09:00:09
     * @modify 20200316 何光鑫 v1.1.2 创建
     * @since v1.1.2
     */
    public LayuiPageInfo querySimChangeHistory(String transId, String accountId,Map<String, String> parameterMap) throws IOException {
        // 调用api接口：先获取token，然后带着token调用api接口
        String url = UrlConstants.SIM_CHANGE_HISTORY;
        ResultDTO tokenResultDTO = doRequest(true, accountId, transId, parameterMap,url);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
            log.warn("[{}] query simChangeHistory token error first,error message is {}.",transId, errorCode);
            return LayuiPageFactory.cteateErrorMsg(errorCode);
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = tokenResultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token[accountId:{}] of query simChangeHistory is invalid and start to get a new token.", transId, accountId);
            tokenResultDTO = doRequest(false, accountId, transId, parameterMap,url);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
                log.warn("[{}] query simChangeHistory token error second,error message is {}.",transId, errorCode);
                return LayuiPageFactory.cteateErrorMsg(errorCode);
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = tokenResultDTO.getMsg();
        }
        log.info("[{}] query simChangeHistory result string is {}.", transId, responseStr);
        // 组装页面信息
        ResponseDto<HistoryStatusListDTO> result = JsonUtil.parseJson(responseStr, new TypeReference<ResponseDto<HistoryStatusListDTO>>() {});
        code = result.getStatus();
        if (!ErrorCode.SUCCESS.getCode().equals(code)) {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] query simChangeHistory error,error message is {}.", transId, result.getMessage());
            return LayuiPageFactory.cteateErrorMsg(ErrorCode.getByCode(code));
        }
        List<HistoryStatusListDTO> historyStatusListDTOS = result.getResult();
        if (ToolUtil.isEmpty(historyStatusListDTOS)) {
            log.warn("[{}] query simChangeHistory end,result is null.", transId);
            return LayuiPageFactory.createEmptyPageInfo();
        }
        List<HistoryStatusDTO> historyStatusDTOList = historyStatusListDTOS.get(0).getChangeHistoryList();
        //封装参数
        List<Map<String,Object>> resultListMaps = new ArrayList<>();
        if(ToolUtil.isNotEmpty(historyStatusDTOList)){
            for(HistoryStatusDTO historyStatusDTO:historyStatusDTOList){
                Map<String,Object> resultMap = new HashMap<>();
                resultMap.put(Constants.RESPONSE_DESC_STATUS,historyStatusDTO.getDescStatus());
                resultMap.put(Constants.RESPONSE_TARGET_STATUS,historyStatusDTO.getTargetStatus());
                resultMap.put(Constants.CHANGE_DATE,historyStatusDTO.getChangeDate());
                resultListMaps.add(resultMap);
            }
        }
        Page page = LayuiPageFactory.defaultPage();
        page.setRecords(resultListMaps);
        Page wrapped = new GeneralHistoryStatusWrapper(page).wrap();
        return LayuiPageFactory.createPageInfo(wrapped);
    }

    /**
     * 调用api接口查询节电参数变更
     *
     * @param transId
     * @param accountId 集团账户id
     * @param msisdns 物联卡号
     * @param apnName APN名称
     * @param precisionType 定时器精度
     * @param precisionVal 对应精度值
     * @return 返回
     * @throws IOException
     * @author 何光鑫
     * @date 20200316 15:32:29
     * @modify 20200316 何光鑫 v1.1.2 创建
     * @since v1.1.2
     */
    public ResponseData changeParamNode(String transId, String accountId, String msisdns,String apnName,String precisionType,String precisionVal) throws IOException {
        ResponseData responseData = new ResponseData();
        // 封装调用api接口的参数
        Map<String, String> parameterMap = new HashMap<>();
        String url = UrlConstants.SIM_PARAMETER_NODE;
        parameterMap.put(Constants.REQUEST_PARAM_APNNAME,apnName);
        parameterMap.put(Constants.REQUEST_PARAM_MSISDNS,msisdns);
        if(apnName.equals(Constants.RESPONSE_CMNBIOT) || apnName.equals(Constants.RESPONSE_CMNBIOT2)||apnName.equals(Constants.RESPONSE_CMNBIOT6)){
            parameterMap.put(Constants.RESPONSE_PRECISION_TYPE,precisionType);
            parameterMap.put(Constants.RESPONSE_PRECISION_VAL,precisionVal);
        }
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO tokenResultDTO = doRequest(true, accountId, transId, parameterMap,url);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
            log.warn("[{}] changeParamNode token error first,error message is {}.",transId, errorCode.getMsg());
            responseData.setCode(Integer.valueOf(errorCode.getCode()));
            responseData.setMessage(errorCode.getMsg());
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = tokenResultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token[accountId:{}] of changeParamNode is invalid and start to get a new token.", transId, accountId);
            tokenResultDTO = doRequest(false, accountId, transId,  parameterMap,url);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(tokenResultDTO.getCode());
                log.warn("[{}] changeParamNode token error second,error message is {}.",transId, errorCode.getMsg());
                responseData.setCode(Integer.valueOf(errorCode.getCode()));
                responseData.setMessage(errorCode.getMsg());
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = tokenResultDTO.getMsg();
        }

        log.info("[{}] changeParamNode result string is {}.", transId, responseStr);
        // 解析api响应结果
        ResponseDto<Map<String, String>> responseDto = JsonUtil.parseJson(responseStr,
                new TypeReference<ResponseDto<Map<String, String>>>(){});
        code = responseDto.getStatus();
        if (ErrorCode.SUCCESS.getCode().equals(code)) {
            String responseJobId = responseDto.getResult().get(0).get(Constants.RESPONSE_JOB_ID);
            BusinessJobIdDTO businessJobIdDTO = new BusinessJobIdDTO();
            businessJobIdDTO.setJobId(responseJobId);
            return ResponseData.success(businessJobIdDTO);
        } else {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] changeParamNode error, error message is {}.", transId, responseDto.getMessage());
            responseData.setCode(Integer.valueOf(code));
            responseData.setMessage(responseDto.getMessage());
            return responseData;
        }
    }

    /**
     * request 请求
     *
     * @param tokenValid   true表示使用已经初始化了的token值，false表示使用重新生成的token值
     * @param accountId 集团id
     * @param transId
     * @param parameterMap 调用api接口的参数
     * @param url 调用API接口的请求路径
     * @return 返回 API接口响应结果（或者获取token失败的原因）
     * @throws IOException
     * @author 何光鑫
     * @date 20200313 14:52:27
     * @modify 20200313 何光鑫 v1.1.2 创建
     * @since v1.1.2
     */
    private ResultDTO doRequest(boolean tokenValid, String accountId, String transId, Map<String, String> parameterMap, String url) throws IOException {
        // 根据 accountId 查询 token
        ResultDTO tokenResultDTO = tokenService.getToken(tokenValid, accountId);
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            return tokenResultDTO;
        }
        parameterMap.put(Constants.REQUEST_PARAM_TOKEN, tokenResultDTO.getMsg());
        parameterMap.put(Constants.REQUEST_PARAM_TRANSID, transId);
        String methodUrl = apiRequestUtil.buildRequestUrl(parameterMap, url);
        log.info("[{}] query general request url is {}.", transId, methodUrl);
        tokenResultDTO.setMsg(apiRequestUtil.doGet(methodUrl));
        return tokenResultDTO;
    }
}
